/**
 * Copyright 2010 Kurtis Nusbaum
 *
 * This file is part of RemoteRunner.  
 *
 * RemoteRunner is free software: you can 
 * redistribute it and/or modify it under the terms of the GNU General Public 
 * License as published by the Free Software Foundation, either version 2 of the 
 * License, or (at your option) any later version.  
 *
 * RemoteRunner is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
 * for more details.  You should have received a copy of the GNU  General 
 * Public License along with RemoteRunner. If not, see 
 * http://www.gnu.org/licenses/.
 */

package org.klnusbaum.remoterunner;

import android.app.ListActivity;
import android.os.Bundle;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.Toast;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.util.Log;
import android.content.Intent;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.database.Cursor;
import android.widget.SimpleCursorAdapter;
import android.content.Context;
import android.os.AsyncTask;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;

import java.util.concurrent.Semaphore;
import java.io.IOException;
import java.io.File;

import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.KnownHosts;
import ch.ethz.ssh2.ServerHostKeyVerifier;
import ch.ethz.ssh2.Session;

/**
 * Class used for Commanding a host
 */
public class CommandHostActivity extends ListActivity{
   
	/** ID of the host being commanded. */
	int hostID;
	/** Hostname of the host being commanded. */
  String hostname;
	/** Username of the host being commanded. */
  String username;
	/** Password being used to log into the host. */
  private String password;

	/** Used for when restoring the activity */
	private static final String EXTRA_PASSWORD = "PASSWORD";

	/** Database containing all the hosts. */
  private HostsDB hostsDatabase;

	/** Tag for logging purposes. */
  private static final String TAG = "COMMANDHOST";

	/** Flag used to indicate that the user has been
	prompted for a password at least once. */
	private static final String WASPROMPTEDFLAG = "wasprompted";


	/**
	 * Constants for helping save dialog state
	 */
	private static final String EXTRA_COMMAND_DIALOG_STATE = 
		"COMMAND_DIALOG_STATE";
	private static final String EXTRA_DIALOG_COMMAND_ID = "COMMAND_DIALOG_ID";
	private static final String EXTRA_PASSWORD_DIALOG_STATE =
		"PASSWORD_DIALOG_STATE";
	private static final String EXTRA_SHOW_YESNO_DIALOG = "SHOW_YESNO_DIALOG";
	private static final String EXTRA_SHOW_PROGRESS_DIALOG = 
		"SHOW_PROGRESS_DIALOG";
	private static final String EXTRA_COMMAND_BEING_DELETED = 
		"COMMAND_BEING_DELETED";


	/** Adapter for displaying commands */
	private CommandAdapter commandAdapter;

	/** Cursor pointing to all  of the commands associated with the host. */
	private Cursor commandsCursor;

	/** The current EditCommandDialog being shown. If no dialog is being shown
	 * the this is null.
	 */
	private EditCommandDialog currentCommandDialog = null;

	/** The current SetPasswordDialog being shown. If no dialog is being shown
	 * the this is null.
	 */
	private SetPasswordDialog currentPasswordDialog = null;

	/**
	 * The current YesNo dialog being shown. If no dialog is being shown this
	 * this is null.
	 */
	private AlertDialog currentYesNoDialog = null;

	/**
	 * The current ProgressDialog being shown. If no dialog is being shown this
	 * this is null.
	 */
	private ProgressDialog currentProgressDialog = null;

	/** Current confirm delete dialog that is showing.
		If there isn't one this is null. */
	private AlertDialog currentConfirmDeleteDialog = null;

	/**
	 * Current command trying to be deleted. HostsDB.INVALID_COMMAND_ID if
	 * no host is being currently deleted.
	 */
	private int currentCommandToBeDeleted = HostsDB.INVALID_COMMAND_ID;

	/**
   * Holds the current active instance of this Activity. This is here so
	 * so that when a CommandTask wants to dismiss a dialog it calls it on
   * the correct activity, even if that activity isn't the one that originally
	 * created it.
	 */
	private static CommandHostActivity ACTIVE_INSTANCE;

	/**
	 * The current command task that is being run. This is here so that when
	 * onCreateDialog is called for the COMMAND_PROGRESS_DIALOG, the dialog
 	 * knows which task to cancel in the OnCancelListener. It's static so that
	 * it is presistent even if a new Activity is created because an old one
	 * was destroyed due to an orientation change.
	 */
	private static CommandTask currentCommandTask;
	
	/** Constant used for identifying the PLEASE_ENTER_PASSWORD_DIALOG. */
	private static final int PLEASE_ENTER_PASSWORD_DIALOG = 1;

	/** Group of objects used to help answer yes or no questions prompted
   * by the server.
	 */
	private static final Semaphore yesNoSem = new Semaphore(1, true);
	private static boolean yesNoAnswer = false;
	private static String currentYesNoQuestion;

	/**
	 * Group of objects used to help store the known host keys
	 */
	private static final String knownHostPath = "known_hosts";
	private static KnownHosts database = new KnownHosts();
	static {
		try{
			database.addHostkeys(new File(knownHostPath));
		}catch(Exception e){}
	}

	private final DialogInterface.OnClickListener passwordListener = 
		new DialogInterface.OnClickListener(){
		@Override
		public void onClick(DialogInterface dialogInterface, int button){
			if(button == DialogInterface.BUTTON_POSITIVE){
				SetPasswordDialog setPasswordDialog = 
					(SetPasswordDialog)dialogInterface;
				password = setPasswordDialog.getPassword();
				setPasswordDialog.dismiss();
			}	
			else if(button == DialogInterface.BUTTON_NEGATIVE){
				dialogInterface.cancel();
			}
		}
	};

	private final DialogInterface.OnDismissListener passwordOnDismiss =
		new DialogInterface.OnDismissListener(){
		@Override
		public void onDismiss(DialogInterface dialogInterface){
			currentPasswordDialog = null;
		}
	};		

	private final DialogInterface.OnClickListener commandListener = 
		new DialogInterface.OnClickListener(){
		@Override
		public void onClick(DialogInterface dialogInterface, int button){
			if(button == DialogInterface.BUTTON_POSITIVE){
				EditCommandDialog commandDialog = 
					(EditCommandDialog)dialogInterface;
				if(!commandDialog.isEditing()){
        	addCommand(commandDialog.getCommand(), 
						commandDialog.getCommandDesc());
				}
				else{
					changeCommand(
						commandDialog.getCommandID(),
						commandDialog.getCommand(),
						commandDialog.getCommandDesc());
				}
				commandDialog.dismiss();
			}	
			else if(button == DialogInterface.BUTTON_NEGATIVE){
				dialogInterface.cancel();
			}
		}
	};

	private final DialogInterface.OnDismissListener commandOnDismiss =
		new DialogInterface.OnDismissListener(){
		@Override
		public void onDismiss(DialogInterface dialogInterface){
			currentCommandDialog = null;
		}
	};		

	private final DialogInterface.OnClickListener yesNoListener =
		new DialogInterface.OnClickListener(){
		@Override
		public void onClick(DialogInterface dialogInterface, int button){
			if(button == DialogInterface.BUTTON_POSITIVE){
				yesNoAnswer = true;
			}
			else if(button == DialogInterface.BUTTON_NEGATIVE){
				yesNoAnswer = false;
			}
			yesNoSem.release();
			dialogInterface.dismiss();
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
    hostsDatabase = new HostsDB(this);
		ACTIVE_INSTANCE = this;

		hostID = getIntent().getIntExtra(HostListActivity.EXTRA_HOSTID, -1);
    hostname = hostsDatabase.getHostname(hostID); 
		Log.i(TAG, "Commanding host \"" + hostname + "\"");
    username = hostsDatabase.getUsername(hostID);
		commandsCursor = hostsDatabase.getCommands(hostID);
		commandAdapter = new CommandAdapter(
			this, 
			R.layout.command_list_item,
			commandsCursor,
			new String[] {HostsDB.COLUMN_COMMAND, HostsDB.COLUMN_COMMAND_DESC},
			new int[] {R.id.command, R.id.command_description}
		);
    setListAdapter(commandAdapter);


		ListView lv = getListView();
		lv.setTextFilterEnabled(true);

		lv.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				sendCommand(((CommandAdapter) parent.getAdapter()).getCommand(position));
			}
		});

		registerForContextMenu(lv);
		if(
			savedInstanceState == null || 
			savedInstanceState.get(WASPROMPTEDFLAG) == null)
		{
			currentPasswordDialog = 
				new SetPasswordDialog(this, passwordListener, passwordOnDismiss);
			currentPasswordDialog.show();
		}

			
	}

	@Override
	protected void onDestroy(){
		super.onDestroy();
		commandsCursor.close();
		hostsDatabase.close();
	}

	@Override
	protected void onSaveInstanceState(Bundle outState){
		super.onSaveInstanceState(outState);
		outState.putBoolean(WASPROMPTEDFLAG, true);
		if(currentCommandDialog != null){
			outState.putInt(
				EXTRA_DIALOG_COMMAND_ID, 
				currentCommandDialog.getCommandID());
			outState.putBundle(
				EXTRA_COMMAND_DIALOG_STATE, 
				currentCommandDialog.onSaveInstanceState());
			currentCommandDialog.cancel();
		}
		else if(currentPasswordDialog != null){
			outState.putBundle(
				EXTRA_PASSWORD_DIALOG_STATE, 
				currentPasswordDialog.onSaveInstanceState());
			currentPasswordDialog.cancel();
		}

		if(currentYesNoDialog != null){
			outState.putBoolean(EXTRA_SHOW_YESNO_DIALOG, true);	
			currentYesNoDialog.dismiss();
		}
		
		if(currentProgressDialog != null){
			outState.putBoolean(EXTRA_SHOW_PROGRESS_DIALOG, true);
			currentProgressDialog.dismiss();
		}

		if(currentConfirmDeleteDialog != null){
			outState.putInt(
				EXTRA_COMMAND_BEING_DELETED, 
				currentCommandToBeDeleted);
			currentConfirmDeleteDialog.dismiss();
		}

		outState.putString(EXTRA_PASSWORD, password);
	}	

	@Override
	protected void onRestoreInstanceState(Bundle savedInstanceState){
		super.onRestoreInstanceState(savedInstanceState);
		if(savedInstanceState != null && 
			savedInstanceState.keySet().contains(EXTRA_COMMAND_DIALOG_STATE))
		{
			currentCommandDialog = new EditCommandDialog(
				this, 
				commandListener, 
				commandOnDismiss,
				savedInstanceState.getInt(EXTRA_DIALOG_COMMAND_ID), 
				hostsDatabase);
			currentCommandDialog.onRestoreInstanceState(
				savedInstanceState.getBundle(EXTRA_COMMAND_DIALOG_STATE));
			currentCommandDialog.show();
		}
		else if(savedInstanceState != null && 
			savedInstanceState.keySet().contains(EXTRA_PASSWORD_DIALOG_STATE))
		{
			currentPasswordDialog = 
				new SetPasswordDialog(this, passwordListener, passwordOnDismiss);	
			currentPasswordDialog.onRestoreInstanceState(
				savedInstanceState.getBundle(EXTRA_PASSWORD_DIALOG_STATE));
			currentPasswordDialog.show();
		}
		else if(savedInstanceState != null &&
			savedInstanceState.keySet().contains(EXTRA_COMMAND_BEING_DELETED))
		{
			showConfirmDeleteDialog(
				savedInstanceState.getInt(EXTRA_COMMAND_BEING_DELETED));
		}

		if(savedInstanceState != null &&
			savedInstanceState.keySet().contains(EXTRA_SHOW_PROGRESS_DIALOG))
		{
			showProgressDialog();
		}
		
		if(savedInstanceState != null &&
			savedInstanceState.keySet().contains(EXTRA_SHOW_YESNO_DIALOG))
		{
			showYesNoDialog();
		}

		password = savedInstanceState.getString(EXTRA_PASSWORD);
	}
	

	@Override
	public boolean onCreateOptionsMenu(Menu menu){
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.command_menu, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.menuAddCommand:
			currentCommandDialog = 
				new EditCommandDialog(this, commandListener, 
				commandOnDismiss, hostsDatabase);
			currentCommandDialog.show();
			return true;
		case R.id.menuSetPassword:
			currentPasswordDialog = 
				new SetPasswordDialog(this, passwordListener, passwordOnDismiss);
			currentPasswordDialog.show();
			return true;
		default:
			return super.onOptionsItemSelected(item);
		}
	}

  @Override
  public void onCreateContextMenu(ContextMenu menu, View v,
    ContextMenuInfo menuInfo)
  {
		super.onCreateContextMenu(menu, v, menuInfo);
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.command_context_menu, menu);
		menu.setHeaderTitle(R.string.command_actions);
  }

  @Override
  public boolean onContextItemSelected(MenuItem item){
    AdapterContextMenuInfo info = 
      (AdapterContextMenuInfo)item.getMenuInfo();
    int commandToModify =
      ((CommandAdapter)getListAdapter()).getCommandID(info.position);
    switch(item.getItemId()){
    case R.id.delete_command:
			SharedPreferences prefs = 
				PreferenceManager.getDefaultSharedPreferences(this);
			if(prefs.getBoolean(getString(R.string.command_delete_confirm_key), true)){
				showConfirmDeleteDialog(commandToModify);
			}
			else{
				deleteCommand(commandToModify);
			}
      return true;
		case R.id.edit_command:
			currentCommandDialog = new EditCommandDialog(
				this, commandListener, commandOnDismiss, 
				commandToModify, hostsDatabase);
			currentCommandDialog.show();
			return true;
    default:
      return super.onContextItemSelected(item);
    }
  }


	protected Dialog onCreateDialog(int id){
		switch(id){
		case PLEASE_ENTER_PASSWORD_DIALOG:
			AlertDialog.Builder builder = 
				new AlertDialog.Builder(CommandHostActivity.this);	
			builder.setMessage(R.string.please_enter_password)
			.setTitle(R.string.password_not_set)
			.setCancelable(false)
      .setPositiveButton(getString(android.R.string.ok), 
				new DialogInterface.OnClickListener(){
         	public void onClick(DialogInterface dialog, int id){
           	dialog.dismiss();
         	}
				});
			return builder.create();
		default:
			return super.onCreateDialog(id);
		}
	}

	/**
	 * Add a command for this host.
	 * 
	 * @param commandToAdd Name of the command to add.
	 * @param commandDesc The description of the command being added.
	 */
  private void addCommand(String commandToAdd, String commandDesc){
    if(hostsDatabase.addCommand(hostID, commandToAdd, commandDesc) > 0){
			commandAdapter.refresh();
		}
		else{
			Toast.makeText(
				this, "Error adding host",
				Toast.LENGTH_SHORT).show();
		}
  }

	/**
	 * Change a command.
	 *
	 * @param commandID The ID of the command to change.
	 * @param newCommand The new name of the command.
	 * @param commandDesc The new description of the command.
	 */
	private void changeCommand(
		int commandID, String newCommand, String commandDesc)
	{
		if(hostsDatabase.updateCommand(commandID, newCommand, commandDesc) <= 0){
			Log.e(TAG, "Error changing command in hostsDatabase.");
			Toast.makeText(this, "Error: Command Not Changed",
			Toast.LENGTH_SHORT).show();
		}
		else{
			Log.i(TAG, "Changing command with ID \"" + commandID + "\" to \""+
				newCommand + "\"");
			commandAdapter.refresh();
		}
	}
        
	/**
	 * Delete a command
	 *
	 * @param commandID The ID of the command to be deleted.
	 */
  private void deleteCommand(int commandID){
    if(hostsDatabase.deleteCommand(commandID) > 0){
			commandAdapter.refresh();
		}
		else{
			Log.e(TAG, "Error deleting command");
			Toast.makeText(this, "Error: Command Not Deleted",
			Toast.LENGTH_SHORT).show();
		}
  }

	/**
	 * Sends a command to the host.
	 * 
	 * @param command The command to send.
	 */
	public void sendCommand(String command){
		if(password != null && !password.equals("")){
			Log.i(TAG, "Sending command \"" + command + "\"");
			new CommandTask().execute(
				password, command, username, hostname);
		}
		else{
			showDialog(PLEASE_ENTER_PASSWORD_DIALOG);
		}	
  }

	/**
	 * Show the yes no dialog
	 */
	private void showYesNoDialog(){
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setMessage(currentYesNoQuestion)
		.setCancelable(false)
		.setPositiveButton(android.R.string.yes, yesNoListener)
		.setNegativeButton(android.R.string.no, yesNoListener);
		currentYesNoDialog = builder.create();
		currentYesNoDialog.setOnDismissListener(
			new DialogInterface.OnDismissListener(){
				public void onDismiss(DialogInterface dialogInterface){
					currentYesNoDialog = null;
				}
			});
		currentYesNoDialog.show();
	}

	/**
	 * Show the progress dialog 
	 */
	private void showProgressDialog(){
		if(currentCommandTask != null){
			currentProgressDialog = 
				new ProgressDialog(CommandHostActivity.this);
			currentProgressDialog.setIndeterminate(true);
			currentProgressDialog.setMessage("Sending Command...");
			currentProgressDialog.setOnCancelListener(
				new DialogInterface.OnCancelListener(){
					public void onCancel(DialogInterface dialog){
						currentCommandTask.cancel(false);
					}
				});
			currentProgressDialog.setOnDismissListener(
				new DialogInterface.OnDismissListener(){
					public void onDismiss(DialogInterface dialog){
						currentProgressDialog = null;
					}
				});
			currentProgressDialog.show();
		}
	}

	public void showConfirmDeleteDialog(int commandToBeDeleted){
		currentCommandToBeDeleted = commandToBeDeleted;
		final DialogInterface.OnClickListener confirmDeleteListener =
			new DialogInterface.OnClickListener(){
				public void onClick(DialogInterface dialog, int which){
					if(which == AlertDialog.BUTTON_POSITIVE){
						deleteCommand(currentCommandToBeDeleted);
					}
					dialog.dismiss();
				}
			};
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle(R.string.delete_command)
		.setMessage(R.string.delete_command_message)
		.setPositiveButton(android.R.string.ok, confirmDeleteListener)
		.setNegativeButton(android.R.string.cancel, confirmDeleteListener);
		currentConfirmDeleteDialog = builder.create();
		currentConfirmDeleteDialog.setOnDismissListener(
			new DialogInterface.OnDismissListener(){
				public void onDismiss(DialogInterface dialog){
					currentConfirmDeleteDialog = null;
					currentCommandToBeDeleted = HostsDB.INVALID_COMMAND_ID;
				}
			});
		currentConfirmDeleteDialog.show();
	}
	/**
	 * Adpater for displaying commands.
	 */
	public class CommandAdapter extends SimpleCursorAdapter{

		/**
		 * Constructor for creating a CommandAdapter.
		 * @param context Context in which the adapter is being used.
		 * @param layout Layout to be used for displaying the commands.
		 * @param c The Cursor used to get the commands information.
		 * @param from List of curor columns to be displayed.
		 * @param to List of layout itmes where the columns from the cursor should 
				be displayed.
		 */
		public CommandAdapter(
			Context context, int layout, Cursor c, String[] from, int[] to)
		{
			super(context, layout, c, from, to);
		}

		/**
		 * Get the command id of a command located at a position in the list.
		 *
		 * @param position Position in the list of the desired command.
		 * @return The id of the command located at the position in the list.
	 	 */
		public int getCommandID(int position){
			Cursor cursorAtPos = (Cursor)getItem(position);
			return cursorAtPos.getInt(cursorAtPos.getColumnIndex(HostsDB.KEY_ID));
		}

		/**
		 * Get the command located at a position in the list.
		 *
		 * @param position Position in the list of the desired command.
		 * @return The command located at the position in the list.
	 	 */
		public String getCommand(int position){
			Cursor cursorAtPos = (Cursor)getItem(position);
			return cursorAtPos.getString(
				cursorAtPos.getColumnIndex(HostsDB.COLUMN_COMMAND));
		}

		/**
		 * Refresh what is displayed in the adapter.
	   */
		public void refresh(){
			getCursor().requery();
		}

	}

	/**
	 * AsyncTask for issueing commands.
   */
	private class CommandTask extends AsyncTask<String, Void, String>{

		/** Constants sending messages. */
		private static final String COMMAND_SENT = "Command Sent";
		private static final String COMMAND_FAILED = "Connection Error";
		private static final String COMMAND_CANCELED = "Command Canceled";
		/** Connection  used for sending command */
		private Connection conn;

		/** Session used for sending command */
		private Session sess;

		@Override
		protected void onPreExecute(){
			currentCommandTask = this;
			showProgressDialog();
		}
		
		@Override
		protected String doInBackground(String... args){
			String result;
			String password = args[0];
			String command = args[1];
			String username = args[2];
			String hostname = args[3];
    	try{
				
				conn = new Connection(hostname);
				conn.connect(new AdvancedVerifier());
				boolean isAuthenticated = 
					conn.authenticateWithPassword(username, password);
				if (isAuthenticated == false){
					throw new IOException("Authentication failed.");
				}
				sess = conn.openSession();
				sess.execCommand(command);
				conn.close();
				Log.i(TAG, "Command \"" + command + "\" sent.");
				result = COMMAND_SENT;
    	}
    	catch(Exception e){
				result = "Failed: " + e.getMessage();
      	Log.e(TAG, e.getMessage());
    	}
			return result;
		}

		@Override
		protected void onPostExecute(String result){
			if(currentProgressDialog != null){
				ACTIVE_INSTANCE.currentProgressDialog.dismiss();
			}
			currentCommandTask = null;
			Toast.makeText(
				CommandHostActivity.this, result, Toast.LENGTH_LONG).show();
		}

		@Override
		protected void onCancelled(){
			if(conn != null){
				conn.close();
			}
			Toast.makeText(
				CommandHostActivity.this, COMMAND_CANCELED, Toast.LENGTH_LONG).show();
		}
	}

	/**
	 * This ServerHostKeyVerifier asks the user on how to proceed if a key cannot be found
	 * in the in-memory database.
	 *
	 */
	class AdvancedVerifier implements ServerHostKeyVerifier
	{
		public boolean verifyServerHostKey(String hostname, int port, String serverHostKeyAlgorithm,
				byte[] serverHostKey) throws Exception
		{
			final String host = hostname;
			final String algo = serverHostKeyAlgorithm;

			String message;

			/* Check database */

			int result = database.verifyHostkey(hostname, serverHostKeyAlgorithm, serverHostKey);

			switch (result)
			{
			case KnownHosts.HOSTKEY_IS_OK:
				return true;

			case KnownHosts.HOSTKEY_IS_NEW:
				message = "Do you want to accept the hostkey (type " + algo + ") from " + host + " ?\n";
				break;

			case KnownHosts.HOSTKEY_HAS_CHANGED:
				message = "WARNING! Hostkey for " + host + " has changed!\nAccept anyway?\n";
				break;

			default:
				throw new IllegalStateException();
			}

			/* Include the fingerprints in the message */

			String hexFingerprint = KnownHosts.createHexFingerprint(serverHostKeyAlgorithm, serverHostKey);
			//String bubblebabbleFingerprint = KnownHosts.createBubblebabbleFingerprint(serverHostKeyAlgorithm,
					//serverHostKey);

			message += "Hex Fingerprint: " + hexFingerprint;
			// + "\nBubblebabble Fingerprint: " + bubblebabbleFingerprint;

			/* Now ask the user */

			currentYesNoQuestion = message;
			try{
				yesNoSem.acquire();
				if(Thread.currentThread().isInterrupted()){
					return yesNoAnswer;
				}
				runOnUiThread(new Runnable(){
					public void run(){
						showYesNoDialog();
					}
				});
				yesNoSem.acquire();
				yesNoSem.release();
			}
			catch(InterruptedException e){}

			if (yesNoAnswer)
			{
				/* Be really paranoid. We use a hashed hostname entry */

				String hashedHostname = KnownHosts.createHashedHostname(hostname);

				/* Add the hostkey to the in-memory database */

				database.addHostkey(new String[] { hashedHostname }, serverHostKeyAlgorithm, serverHostKey);

				/* Also try to add the key to a known_host file */

				try
				{
					KnownHosts.addHostkeyToFile(new File(knownHostPath), new String[] { hashedHostname },
							serverHostKeyAlgorithm, serverHostKey);
				}
				catch (IOException ignore)
				{
				}

				return true;
			}

			/*if (!yesNoAnswer)
			{
				throw new Exception("Hostkey rejected");
			}*/

			return false;
		}
	}

}
